import {
  canUse,
  isNull,
  PagedList,
  PageParams,
  isUndefined,
  numberToString,
  _pick,
} from "mmb";
import * as brand_spokesmanpb from "../grpc-client/service/brand_spokesman_pb";
import {
  getBgsBrandSpokesmanOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import GrpcErrCode from "../grpc-client/grpcErrCode";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";
import {
  BrandSpokesman,
  BecomeBrandSpokesmanParams,
  UpdateBrandSpokesmanParams,
  CancelBrandSpokesmanParams,
  BrandSpokesmanCacheInfo,
  BrandSpokesmanWithBrand,
  BrandSpokesmanWithUser,
} from "./declareTypes";
import { getCache, setCache, makeEntityKey } from "../proxy/redisProxy";

// // 考虑用缓存
// export const checkBrandSpokesman = async (
//   userId: string,
//   brandSpokesmanId: string
// ) => {
//   let cacheItem = await getBrandSpokesmanInfo(brandSpokesmanId);
//   if (isUndefined(cacheItem)) {
//     console.log(`not found spokesman:${brandSpokesmanId},${userId}`);
//     return false;
//   }
//   if (cacheItem.userId !== userId) {
//     console.log(`mismatch spokesman:${brandSpokesmanId},${userId}`);
//     return false;
//   }

//   return true;
// };

export const getBrandSpokesmanInfo = async (brandSpokesmanId: string) => {
  const k = makeBrandSpokesmanCacheKey(brandSpokesmanId);
  const cv = await getCache(k);
  let cacheItem: BrandSpokesmanCacheInfo | undefined = undefined;
  if (canUse(cv)) {
    console.log("checkBrandSpokesman use cached value");
    cacheItem = JSON.parse(cv!) as BrandSpokesmanCacheInfo;
  } else {
    console.log("checkBrandSpokesman use query");
    const brandSpokesman = await getBrandSpokesman(brandSpokesmanId);
    if (!isUndefined(brandSpokesman)) {
      cacheItem = _pick(
        brandSpokesman,
        "userId",
        "brandId"
      ) as BrandSpokesmanCacheInfo;
      await setCache(k, cacheItem); // replay=>OK
    }
  }
  return cacheItem;
};

export const getBrandSpokesmanInfoSafely = async (brandSpokesmanId: string) => {
  const brandSpokesmanInfo = await getBrandSpokesmanInfo(brandSpokesmanId);
  return brandSpokesmanInfo!;
};

/****************************************************************************************/
/*                                   brand_spokesman entity                                 */
/****************************************************************************************/

const makeBrandSpokesmanCacheKey = makeEntityKey("brand_spokesman");

const brandSpokesmanPbToObject = (
  pb: brand_spokesmanpb.BrandSpokesmanEntity
): BrandSpokesman => {
  return {
    brandSpokesmanId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),
  };
};

/****************************************************************************************/
/*                                   brand_spokesman cmd                                */
/****************************************************************************************/

export const becomeBrandSpokesman = async ({
  userId,
  brandId,
  aliasName,
  became,
}: BecomeBrandSpokesmanParams): Promise<BrandSpokesman> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req = new brand_spokesmanpb.BecomeBrandSpokesmanRequest();

  req.setUserId(Number(userId));
  req.setBrandId(Number(brandId));
  req.setAliasName(aliasName);
  req.setBecame(jsTimestampToPb(became));

  return new Promise((resolve, reject) => {
    cl.becomeBrandSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(brandSpokesmanPbToObject(res.getBrandSpokesman()!));
      }
    );
  });
};

export const updateBrandSpokesman = async ({
  brandSpokesmanId,
  aliasName,
  remark,
}: UpdateBrandSpokesmanParams): Promise<BrandSpokesman> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req = new brand_spokesmanpb.UpdateBrandSpokesmanRequest();

  req.setId(Number(brandSpokesmanId));
  if (!isUndefined(aliasName)) {
    req.setAliasName(aliasName);
  }
  if (!isUndefined(remark)) {
    req.setRemark(remark);
  }

  return new Promise((resolve, reject) => {
    cl.updateBrandSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(brandSpokesmanPbToObject(res.getBrandSpokesman()!));
      }
    );
  });
};

export const cancelBrandSpokesman = async ({
  brandSpokesmanId,
}: CancelBrandSpokesmanParams): Promise<BrandSpokesman> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req = new brand_spokesmanpb.CancelBrandSpokesmanRequest();

  req.setId(Number(brandSpokesmanId));

  return new Promise((resolve, reject) => {
    cl.cancelBrandSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(brandSpokesmanPbToObject(res.getBrandSpokesman()!));
      }
    );
  });
};

/****************************************************************************************/
/*                                   brand_spokesman query                              */
/****************************************************************************************/

export const getBrandSpokesman = async (
  brandWarehouseId: string
): Promise<BrandSpokesman | undefined> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req = new brand_spokesmanpb.GetBrandSpokesmanRequest();

  req.setId(Number(brandWarehouseId));

  return new Promise((resolve, reject) => {
    cl.getBrandSpokesman(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          if (opRet.getCode() === GrpcErrCode.NOT_FOUND) {
            resolve(undefined);
            return;
          } else {
            reject(wrapperGrpcError(opRet.getMsg()));
            return;
          }
        }
        resolve(brandSpokesmanPbToObject(res.getBrandSpokesman()!));
      }
    );
  });
};

export const listNormalBrandSpokesmansByBrandID = async (
  brandId: string,
  pager: PageParams
): Promise<PagedList<BrandSpokesman>> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req = new brand_spokesmanpb.ListNormalBrandSpokesmansByBrandIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setBrandId(Number(brandId));

  return new Promise((resolve, reject) => {
    cl.listNormalBrandSpokesmansByBrandID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandSpokesman> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandSpokesmansList()
          .map((u) => brandSpokesmanPbToObject(u));
        resolve(ret);
      }
    );
  });
};

/****************************************************************************************/
/*                                   brand_spokesman joins entity                       */
/****************************************************************************************/

const brandSpokesmanWithBrandPbToObject = (
  pb: brand_spokesmanpb.BrandSpokesmanWithBrandEntity
): BrandSpokesmanWithBrand => {
  return {
    // brand_spokesman
    brandSpokesmanId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // brand
    brandName: pb.getBrandName(),
    brandPic: pb.getBrandPic(),
    brandFansCount: pb.getBrandFansCount(),
    brandPublishActivityCount: pb.getBrandPublishActivityCount(),
  };
};

const brandSpokesmanWithUserPbToObject = (
  pb: brand_spokesmanpb.BrandSpokesmanWithUserEntity
): BrandSpokesmanWithUser => {
  return {
    // brand_spokesman
    brandSpokesmanId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // spokesman User_Info
    spokesmanUserNickName: pb.getSpokesmanUserNickName(),
    spokesmanUserPic: pb.getSpokesmanUserPic(),
    // user_stat
    fansCount: pb.getFansCount(),
  };
};

/****************************************************************************************/
/*                                   brand_spokesman joins query                        */
/****************************************************************************************/

export const listNormalBrandSpokesmanWithBrandsByUserID = async (
  userId: string,
  pager: PageParams
): Promise<PagedList<BrandSpokesmanWithBrand>> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req =
    new brand_spokesmanpb.ListNormalBrandSpokesmanWithBrandsByUserIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setUserId(Number(userId));

  console.log("------nadfdf-----");

  return new Promise((resolve, reject) => {
    cl.listNormalBrandSpokesmanWithBrandsByUserID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandSpokesmanWithBrand> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandSpokesmanWithBrandsList()
          .map((it) => brandSpokesmanWithBrandPbToObject(it));
        resolve(ret);
      }
    );
  });
};

export interface ListNormalBrandSpokesmanWithUsersByBrandIDParam {
  brandId: string;
  keyword?: string;
}

export const listNormalBrandSpokesmanWithUsersByBrandID = async (
  { brandId, keyword }: ListNormalBrandSpokesmanWithUsersByBrandIDParam,
  pager: PageParams
): Promise<PagedList<BrandSpokesmanWithUser>> => {
  const cl = getBgsBrandSpokesmanOpSafely();
  const req =
    new brand_spokesmanpb.ListNormalBrandSpokesmanWithUsersByBrandIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setTs(jsTimestampToPb(pager.ts));
  req.setBrandId(Number(brandId));
  if (!isUndefined(keyword)) {
    req.setKeyword(keyword);
  }

  return new Promise((resolve, reject) => {
    cl.listNormalBrandSpokesmanWithUsersByBrandID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandSpokesmanWithUser> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandSpokesmanWithUsersList()
          .map((it) => brandSpokesmanWithUserPbToObject(it));
        resolve(ret);
      }
    );
  });
};
